﻿// --------------------------------------------------------------------------------------------------------------------
// <copyright file="ResolverDefault.cs" company="Rolosoft Ltd">
//   © Rolosoft Ltd
// </copyright>
// --------------------------------------------------------------------------------------------------------------------

#region License

// // Copyright 2013 Rolosoft Ltd
// // Licensed under the Apache License, Version 2.0 (the "License");
// // you may not use this file except in compliance with the License.
// // You may obtain a copy of the License at
// // http://www.apache.org/licenses/LICENSE-2.0
// // Unless required by applicable law or agreed to in writing, software
// // distributed under the License is distributed on an "AS IS" BASIS,
// // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// // See the License for the specific language governing permissions and
// // limitations under the License.
#endregion

namespace Rsft.Net.Dns
{
    #region Usings

    using System;
    using System.Collections.Generic;
    using System.Diagnostics.Contracts;
    using System.Globalization;
    using System.IO;
    using System.Net;
    using System.Net.Sockets;
    using System.Threading;

    using Rsft.Net.Dns.Diagnostics;
    using Rsft.Net.Dns.Entities;
    using Rsft.Net.Dns.Extensions;
    using Rsft.Net.Dns.Interfaces;
    using Rsft.Net.Dns.Threading;

    using Wintellect.Threading.AsyncProgModel;
    using Wintellect.Threading.ResourceLocks;

    #endregion

    /// <summary>
    ///     The resolver default.
    /// </summary>
    internal sealed class ResolverDefault : ResolverBase, IDisposable
    {
        #region Constants

        /// <summary>
        ///     The max retries exceeded message.
        /// </summary>
        private const string MaxRetriesExceededMessage = @"Maximum retries exceeded.";

        /// <summary>
        ///     The max size of UDP datagram.
        /// </summary>
        /// <remarks>
        ///     RFC1035 max. size of a UDP datagram is 512 bytes.
        /// </remarks>
        private const int MaxSizeUdpDatagram = 512;

        #endregion

        #region Static Fields

        /// <summary>
        ///     The configuration local
        /// </summary>
        /// <remarks>
        ///     Stored in static field for persistence in memory.
        /// </remarks>
        private static IConfiguration configurationLocal;

        #endregion

        #region Fields

        /// <summary>
        ///     The async enumerator get host addresses local.
        /// </summary>
        private AsyncEnumerator<IPAddress[]> asyncEnumeratorGetHostAddressesLocal;

        /// <summary>
        ///     The async enumerator get host by name local.
        /// </summary>
        private AsyncEnumerator<IPHostEntry> asyncEnumeratorGetHostByNameLocal;

        /// <summary>
        ///     The async enumerator get host entry by address local
        /// </summary>
        private AsyncEnumerator<IPHostEntry> asyncEnumeratorGetHostEntryByAddressLocal;

        /// <summary>
        ///     The async enumerator get host entry local
        /// </summary>
        private AsyncEnumerator<IPHostEntry> asyncEnumeratorGetHostEntryByHostNameLocal;

        /// <summary>
        ///     The async enumerator get response.
        /// </summary>
        private AsyncEnumerator<Response> asyncEnumeratorGetResponseLocal;

        /// <summary>
        ///     The async enumerator make entry
        /// </summary>
        private AsyncEnumerator<IPHostEntry> asyncEnumeratorMakeEntryLocal;

        /// <summary>
        ///     The async enumerator query local
        /// </summary>
        private AsyncEnumerator<Response> asyncEnumeratorQueryLocal;

        /// <summary>
        ///     The async enumerator resolve
        /// </summary>
        private AsyncEnumerator<IPHostEntry> asyncEnumeratorResolveLocal;

        /// <summary>
        ///     The async enumerator response TCP.
        /// </summary>
        private AsyncEnumerator<Response> asyncEnumeratorResponseTcpLocal;

        /// <summary>
        ///     The async enumerator response UDP.
        /// </summary>
        private AsyncEnumerator<Response> asyncEnumeratorResponseUdpLocal;

        /// <summary>
        ///     The disposed
        /// </summary>
        private bool disposed;

        /// <summary>
        ///     The one many resource lock for configuration.
        /// </summary>
        private OneManyResourceLock oneManyResourceLockConfiguration;

        /// <summary>
        ///     The one many resource lock for unique header ID for.
        /// </summary>
        private OneManyResourceLock oneManyResourceLockUniqueHeaderId;

        /// <summary>
        ///     The unique header ID for.
        /// </summary>
        private int uniqueHeaderId;

        #endregion

        #region Constructors and Destructors

        /// <summary>
        /// Initializes a new instance of the <see cref="ResolverDefault"/> class.
        /// </summary>
        /// <param name="recordReaderFactory">
        /// The record reader factory.
        /// </param>
        /// <param name="cacheFactory">
        /// The cache factory.
        /// </param>
        /// <param name="configuration">
        /// The configuration.
        /// </param>
        /// <param name="logger">
        /// The logger.
        /// </param>
        public ResolverDefault(
            IRecordReaderFactory recordReaderFactory, 
            ICacheFactory cacheFactory, 
            IConfiguration configuration, 
            ILogger logger)
            : base(recordReaderFactory, cacheFactory, logger)
        {
            Contract.Requires(configuration != null);
            Contract.Requires(configuration.Configuration.DnsServers != null);
            Contract.Requires(configuration.Configuration.DnsTimeout >= 0);
            Contract.Requires(configuration.Configuration.Retries > 0);
            Contract.Requires(
                configuration.Configuration.TransportType == TransportType.Tcp
                || configuration.Configuration.TransportType == TransportType.Udp);
            Contract.Requires(recordReaderFactory != null);
            Contract.Requires(cacheFactory != null);
            Contract.Requires(logger != null);

            this.oneManyResourceLockConfiguration = new OneManyResourceLock();
            this.oneManyResourceLockUniqueHeaderId = new OneManyResourceLock();

            this.Configuration = configuration;
        }

        /// <summary>
        ///     Finalizes an instance of the <see cref="ResolverDefault" /> class.
        /// </summary>
        ~ResolverDefault()
        {
            this.Dispose(false);
        }

        #endregion

        #region Public Properties

        /// <summary>
        ///     Gets or sets the configuration.
        /// </summary>
        /// <value>
        ///     The configuration.
        /// </value>
        /// <remarks>
        ///     Thread safe.
        /// </remarks>
        public override IConfiguration Configuration
        {
            get
            {
                this.oneManyResourceLockConfiguration.Enter(false);
                var rtn = configurationLocal;
                this.oneManyResourceLockConfiguration.Leave();
                return rtn;
            }

            set
            {
                this.oneManyResourceLockConfiguration.Enter(true);
                configurationLocal = value;
                this.oneManyResourceLockConfiguration.Leave();
            }
        }

        #endregion

        #region Properties

        /// <summary>
        ///     Gets or sets the unique header id.
        /// </summary>
        /// <value>
        ///     The unique header id.
        /// </value>
        /// <remarks>
        ///     Thread safe.
        /// </remarks>
        protected override int UniqueHeaderId
        {
            get
            {
                this.oneManyResourceLockUniqueHeaderId.Enter(false);
                var rtn = this.uniqueHeaderId;
                this.oneManyResourceLockUniqueHeaderId.Leave();
                return rtn;
            }

            set
            {
                this.oneManyResourceLockUniqueHeaderId.Enter(true);

                var i = value >= ushort.MaxValue ? new Random().Next(ushort.MinValue, ushort.MaxValue) : value;

                this.uniqueHeaderId = i;

                this.oneManyResourceLockUniqueHeaderId.Leave();
            }
        }

        #endregion

        #region Public Methods and Operators

        /// <summary>
        /// The begin get host addresses.
        /// </summary>
        /// <param name="hostNameOrAddress">
        /// The host name or address.
        /// </param>
        /// <param name="requestCallback">
        /// The request callback.
        /// </param>
        /// <param name="value">
        /// The value.
        /// </param>
        /// <returns>
        /// The <see cref="IAsyncResult"/>.
        /// </returns>
        public override IAsyncResult BeginGetHostAddresses(
            string hostNameOrAddress, AsyncCallback requestCallback, object value)
        {
            this.Logger.Verbose(
                (int)EventId.CommandReceived, 
                string.Format(CultureInfo.InvariantCulture, "BeginGetHostAddresses : {0}", hostNameOrAddress));

            return this.BeginGetHostAddressesLocal(hostNameOrAddress, requestCallback, value);
        }

        /// <summary>
        /// The begin get host by address.
        /// </summary>
        /// <param name="address">
        /// The address.
        /// </param>
        /// <param name="asyncCallback">
        /// The async callback.
        /// </param>
        /// <param name="state">
        /// The state.
        /// </param>
        /// <returns>
        /// The <see cref="IAsyncResult"/>.
        /// </returns>
        public override IAsyncResult BeginGetHostByAddress(string address, AsyncCallback asyncCallback, object state)
        {
            this.Logger.Verbose(
                (int)EventId.CommandReceived, 
                string.Format(CultureInfo.InvariantCulture, "BeginGetHostByAddress : {0}", address));

            return this.BeginGetHostEntry(address, asyncCallback, state);
        }

        /// <summary>
        /// The begin get host by address.
        /// </summary>
        /// <param name="address">
        /// The address.
        /// </param>
        /// <param name="asyncCallback">
        /// The async callback.
        /// </param>
        /// <param name="state">
        /// The state.
        /// </param>
        /// <returns>
        /// The <see cref="IAsyncResult"/>.
        /// </returns>
        public override IAsyncResult BeginGetHostByAddress(IPAddress address, AsyncCallback asyncCallback, object state)
        {
            this.Logger.Verbose(
                (int)EventId.CommandReceived, 
                string.Format(CultureInfo.InvariantCulture, "BeginGetHostByAddress : {0}", address));

            return this.BeginGetHostEntry(address, asyncCallback, state);
        }

        /// <summary>
        /// The begin get host by name.
        /// </summary>
        /// <param name="hostName">
        /// The host name.
        /// </param>
        /// <param name="asyncCallback">
        /// The async callback.
        /// </param>
        /// <param name="value">
        /// The value.
        /// </param>
        /// <returns>
        /// The <see cref="IAsyncResult"/>.
        /// </returns>
        public override IAsyncResult BeginGetHostByName(string hostName, AsyncCallback asyncCallback, object value)
        {
            this.Logger.Verbose(
                (int)EventId.CommandReceived, 
                string.Format(CultureInfo.InvariantCulture, "BeginGetHostByName : {0}", hostName));

            return this.BeginGetHostByNameLocal(hostName, asyncCallback, value);
        }

        /// <summary>
        /// The begin get host entry.
        /// </summary>
        /// <param name="hostNameOrAddress">
        /// The host name or address.
        /// </param>
        /// <param name="asyncCallback">
        /// The async callback.
        /// </param>
        /// <param name="value">
        /// The value.
        /// </param>
        /// <returns>
        /// The <see cref="IAsyncResult"/>.
        /// </returns>
        public override IAsyncResult BeginGetHostEntry(
            string hostNameOrAddress, AsyncCallback asyncCallback, object value)
        {
            this.Logger.Verbose(
                (int)EventId.CommandReceived, 
                string.Format(CultureInfo.InvariantCulture, "BeginGetHostEntry : {0}", hostNameOrAddress));

            return this.BeginGetHostEntryByHostNameOrAddressLocal(hostNameOrAddress, asyncCallback, value);
        }

        /// <summary>
        /// The begin get host entry.
        /// </summary>
        /// <param name="address">
        /// The address.
        /// </param>
        /// <param name="asyncCallback">
        /// The async callback.
        /// </param>
        /// <param name="value">
        /// The value.
        /// </param>
        /// <returns>
        /// The <see cref="IAsyncResult"/>.
        /// </returns>
        public override IAsyncResult BeginGetHostEntry(IPAddress address, AsyncCallback asyncCallback, object value)
        {
            this.Logger.Verbose(
                (int)EventId.CommandReceived, 
                string.Format(CultureInfo.InvariantCulture, "BeginGetHostEntry : {0}", address));

            return this.BeginGetHostEntryLocal(address, asyncCallback, value);
        }

        /// <summary>
        /// The begin get TCP request.
        /// </summary>
        /// <param name="request">
        /// The request.
        /// </param>
        /// <param name="asyncCallback">
        /// The async callback.
        /// </param>
        /// <param name="state">
        /// The state.
        /// </param>
        /// <returns>
        /// The <see cref="IAsyncResult"/>.
        /// </returns>
        /// <exception cref="System.ArgumentNullException">
        /// request is null
        /// </exception>
        public override IAsyncResult BeginGetTcpRequest(Request request, AsyncCallback asyncCallback, object state)
        {
            if (request == null)
            {
                throw new ArgumentNullException("request");
            }

            this.Logger.Verbose(
                (int)EventId.CommandReceived, 
                string.Format(CultureInfo.InvariantCulture, "BeginGetTcpRequest : {0}", request));

            this.asyncEnumeratorResponseTcpLocal = new AsyncEnumerator<Response>();

            return
                this.asyncEnumeratorResponseTcpLocal.BeginExecute(
                    this.GetTcpRequestLocalAsync(
                        this.asyncEnumeratorResponseTcpLocal, 
                        request, 
                        this.Configuration.Configuration.DnsServers.ToArray(), 
                        this.Configuration.Configuration.Retries, 
                        null), 
                    asyncCallback, 
                    state);
        }

        /// <summary>
        /// The begin get UDP request.
        /// </summary>
        /// <param name="request">
        /// The request.
        /// </param>
        /// <param name="asyncCallback">
        /// The async callback.
        /// </param>
        /// <param name="state">
        /// The state.
        /// </param>
        /// <returns>
        /// The <see cref="IAsyncResult"/>.
        /// </returns>
        /// <exception cref="System.ArgumentNullException">
        /// request is null.
        /// </exception>
        public override IAsyncResult BeginGetUdpRequest(Request request, AsyncCallback asyncCallback, object state)
        {
            if (request == null)
            {
                throw new ArgumentNullException("request");
            }

            this.Logger.Verbose(
                (int)EventId.CommandReceived, 
                string.Format(CultureInfo.InvariantCulture, "BeginGetUdpRequest : {0}", request));

            this.asyncEnumeratorResponseUdpLocal = new AsyncEnumerator<Response>();

            return
                this.asyncEnumeratorResponseUdpLocal.BeginExecute(
                    this.GetUdpRequestLocalAsync(
                        this.asyncEnumeratorResponseUdpLocal, 
                        request, 
                        this.Configuration.Configuration.DnsServers.ToArray(), 
                        this.Configuration.Configuration.Retries, 
                        null), 
                    asyncCallback, 
                    state);
        }

        /// <summary>
        /// The begin query.
        /// </summary>
        /// <param name="name">
        /// The name.
        /// </param>
        /// <param name="queryType">
        /// The query type.
        /// </param>
        /// <param name="queryClassType">
        /// The query class type.
        /// </param>
        /// <param name="asyncCallback">
        /// The async callback.
        /// </param>
        /// <param name="state">
        /// The state.
        /// </param>
        /// <returns>
        /// The <see cref="IAsyncResult"/>.
        /// </returns>
        public override IAsyncResult BeginQuery(
            string name, QType queryType, QClassType queryClassType, AsyncCallback asyncCallback, object state)
        {
            this.Logger.Verbose(
                (int)EventId.CommandReceived, 
                string.Format(CultureInfo.InvariantCulture, 
                    "BeginQuery : name={0}, queryType={1}, queryClassType={2}", 
                    name, 
                    queryType, 
                    queryClassType));

            return this.BeginQueryLocal(name, queryType, queryClassType, asyncCallback, state);
        }

        /// <summary>
        /// The begin resolve.
        /// </summary>
        /// <param name="hostName">
        /// The host name.
        /// </param>
        /// <param name="asyncCallback">
        /// The async callback.
        /// </param>
        /// <param name="value">
        /// The value.
        /// </param>
        /// <returns>
        /// The <see cref="IAsyncResult"/>.
        /// </returns>
        public override IAsyncResult BeginResolve(string hostName, AsyncCallback asyncCallback, object value)
        {
            this.Logger.Verbose(
                (int)EventId.CommandReceived, 
                string.Format(CultureInfo.InvariantCulture, "BeginResolve : {0}", hostName));

            return this.BeginResolveLocal(hostName, asyncCallback, value);
        }

        /// <summary>
        ///     The dispose.
        /// </summary>
        public void Dispose()
        {
            this.Dispose(true);
            GC.SuppressFinalize(this);
        }

        /// <summary>
        /// The end get host addresses.
        /// </summary>
        /// <param name="asyncResult">
        /// The async result.
        /// </param>
        /// <returns>
        /// The <see cref="IPAddress[]"/>.
        /// </returns>
        public override IPAddress[] EndGetHostAddresses(IAsyncResult asyncResult)
        {
            var result = (AsyncResult<IPHostEntry>)asyncResult;

            var hostEntry = result.EndInvoke();

            this.Logger.Verbose(
                (int)EventId.CommandProcessed, 
                string.Format(CultureInfo.InvariantCulture, "EndGetHostAddresses : Count# {0}", hostEntry.AddressList.Length));

            return hostEntry.AddressList;
        }

        /// <summary>
        /// The end get host by address.
        /// </summary>
        /// <param name="asyncResult">
        /// The async result.
        /// </param>
        /// <returns>
        /// The <see cref="IPHostEntry"/>.
        /// </returns>
        public override IPHostEntry EndGetHostByAddress(IAsyncResult asyncResult)
        {
            var result = (AsyncResult<IPHostEntry>)asyncResult;

            var hostEntry = result.EndInvoke();

            this.Logger.Verbose(
                (int)EventId.CommandProcessed, 
                string.Format(CultureInfo.InvariantCulture, "EndGetHostByAddress : {0}", hostEntry.HostName));

            return hostEntry;
        }

        /// <summary>
        /// The end get host by name.
        /// </summary>
        /// <param name="asyncResult">
        /// The async result.
        /// </param>
        /// <returns>
        /// The <see cref="IPHostEntry"/>.
        /// </returns>
        public override IPHostEntry EndGetHostByName(IAsyncResult asyncResult)
        {
            var result = (AsyncResult<IPHostEntry>)asyncResult;

            var hostEntry = result.EndInvoke();

            this.Logger.Verbose(
                (int)EventId.CommandProcessed, 
                string.Format(CultureInfo.InvariantCulture, "EndGetHostByName : {0}", hostEntry.HostName));

            return hostEntry;
        }

        /// <summary>
        /// The end get host entry.
        /// </summary>
        /// <param name="asyncResult">
        /// The async result.
        /// </param>
        /// <returns>
        /// The <see cref="IPHostEntry"/>.
        /// </returns>
        public override IPHostEntry EndGetHostEntry(IAsyncResult asyncResult)
        {
            var result = (AsyncResult<IPHostEntry>)asyncResult;

            var response = result.EndInvoke();

            this.Logger.Verbose(
                (int)EventId.CommandProcessed, 
                string.Format(CultureInfo.InvariantCulture, "EndGetHostEntry : {0}", response.HostName));

            return response;
        }

        /// <summary>
        /// The end get TCP request.
        /// </summary>
        /// <param name="asyncResult">
        /// The async result.
        /// </param>
        /// <returns>
        /// The <see cref="Response"/>.
        /// </returns>
        /// <exception cref="System.ArgumentNullException">
        /// asyncResult is null.
        /// </exception>
        public override Response EndGetTcpRequest(IAsyncResult asyncResult)
        {
            if (asyncResult == null)
            {
                throw new ArgumentNullException("asyncResult");
            }

            var response = this.asyncEnumeratorResponseTcpLocal.EndExecute(asyncResult);

            this.Logger.Verbose(
                (int)EventId.CommandProcessed, string.Format(CultureInfo.InvariantCulture, "EndGetTcpRequest"));

            return response;
        }

        /// <summary>
        /// The end get UDP request.
        /// </summary>
        /// <param name="asyncResult">
        /// The async result.
        /// </param>
        /// <returns>
        /// The <see cref="Response"/>.
        /// </returns>
        /// <exception cref="System.ArgumentNullException">
        /// asyncResult is null.
        /// </exception>
        public override Response EndGetUdpRequest(IAsyncResult asyncResult)
        {
            if (asyncResult == null)
            {
                throw new ArgumentNullException("asyncResult");
            }

            var response = this.asyncEnumeratorResponseUdpLocal.EndExecute(asyncResult);

            this.Logger.Verbose(
                (int)EventId.CommandProcessed, string.Format(CultureInfo.InvariantCulture, "EndGetUdpRequest"));

            return response;
        }

        /// <summary>
        /// The end query.
        /// </summary>
        /// <param name="asyncResult">
        /// The async result.
        /// </param>
        /// <returns>
        /// The <see cref="Response"/>.
        /// </returns>
        public override Response EndQuery(IAsyncResult asyncResult)
        {
            var result = (AsyncResult<Response>)asyncResult;

            var response = result.EndInvoke();

            this.Logger.Verbose((int)EventId.CommandProcessed, string.Format(CultureInfo.InvariantCulture, "EndQuery"));

            return response;
        }

        /// <summary>
        /// The end resolve.
        /// </summary>
        /// <param name="asyncResult">
        /// The async result.
        /// </param>
        /// <returns>
        /// The <see cref="IPHostEntry"/>.
        /// </returns>
        public override IPHostEntry EndResolve(IAsyncResult asyncResult)
        {
            var result = (AsyncResult<IPHostEntry>)asyncResult;

            var hostEntry = result.EndInvoke();

            this.Logger.Verbose(
                (int)EventId.CommandProcessed, 
                string.Format(CultureInfo.InvariantCulture, "EndResolve : {0}", hostEntry.HostName));

            return hostEntry;
        }

        #endregion

        #region Methods

        /// <summary>
        /// The TCP request.
        /// </summary>
        /// <param name="request">
        /// The request.
        /// </param>
        /// <returns>
        /// Various stuff.
        /// </returns>
        /// <exception cref="System.ArgumentNullException">
        /// request is null.
        /// </exception>
        /// <exception cref="System.Net.Sockets.SocketException">
        /// Socket exception.
        /// </exception>
        protected override Response TcpRequest(Request request)
        {
            if (request == null)
            {
                throw new ArgumentNullException("request");
            }

            for (var intAttempts = 0; intAttempts < this.Configuration.Configuration.Retries; intAttempts++)
            {
                for (var intDnsServer = 0;
                     intDnsServer < this.Configuration.Configuration.DnsServers.Count;
                     intDnsServer++)
                {
                    var dnsServer = this.Configuration.Configuration.DnsServers[intDnsServer];

                    using (
                        var tcpClient = new TcpClient(dnsServer.AddressFamily)
                                            {
                                                ReceiveTimeout = this.Configuration.Configuration.DnsTimeout,
                                                SendTimeout = this.Configuration.Configuration.DnsTimeout
                                            })
                    {
                        IAsyncResult result;

                        try
                        {
                            result = tcpClient.BeginConnect(dnsServer.Address, dnsServer.Port, null, null);
                        }
                        catch (SocketException exception)
                        {
                            var message = string.Format(
                                CultureInfo.InvariantCulture, ";; Connection to nameserver {0} failed.", dnsServer);

                            this.Verbose(message);

                            this.Logger.Warning(exception, (int)EventId.NetSendReceiveFail);

                            /*next try*/
                            continue;
                        }
                        finally
                        {
                            this.UniqueHeaderId++;
                        }

                        bool success = result.AsyncWaitHandle.WaitOne(this.Configuration.Configuration.DnsTimeout, true);

                        if (!success || !tcpClient.Connected)
                        {
                            var message = string.Format(
                                    CultureInfo.InvariantCulture,
                                    ";; Connection to nameserver {0} failed after timeout of {1}ms.",
                                   dnsServer,
                                   this.Configuration.Configuration.DnsTimeout);
                            
                            this.Verbose(message);
                            this.Logger.Warning((int)EventId.NetSendReceiveFail, message);

                            /*next try*/
                            continue;
                        }

                        using (var bufferedStream = new BufferedStream(tcpClient.GetStream()))
                        {
                            var data = request.Data;
                            
                            var dataList = new List<byte>();
                            foreach (var b in data)
                            {
                                dataList.Add(b);
                            }

                            var bytes = dataList.ToArray();

                            bufferedStream.WriteByte((byte)((bytes.Length >> 8) & 0xff));
                            bufferedStream.WriteByte((byte)(bytes.Length & 0xff));
                            bufferedStream.Write(bytes, 0, bytes.Length);
                            bufferedStream.Flush();

                            var transferResponse = new Response();
                            var soa = 0;
                            var messageSize = 0;

                            while (true)
                            {
                                var intLength = bufferedStream.ReadByte() << 8 | bufferedStream.ReadByte();
                                if (intLength <= 0)
                                {
                                    /*next try*/
                                    break;
                                }

                                messageSize += intLength;

                                bytes = new byte[intLength];
                                bufferedStream.Read(bytes, 0, intLength);

                                var response = new Response(this.RecordReaderFactory, dnsServer, bytes, intLength);

                                if (response.Answers.Count == 0)
                                {
                                    throw new SocketException((int)SocketError.HostNotFound);
                                }

                                if (response.Header.ResponseCode != RCodeType.NoError)
                                {
                                    return response;
                                }

                                if (response.Questions[0].QType != QType.AXFR)
                                {
                                    this.AddToCache(response);
                                    return response;
                                }

                                // Zone transfer
                                if (transferResponse.Questions.Count == 0)
                                {
                                    foreach (Question question in response.Questions)
                                    {
                                        transferResponse.Questions.Add(question);
                                    }
                                }

                                foreach (AnswerResourceRecord answer in response.Answers)
                                {
                                    transferResponse.Answers.Add(answer);
                                }

                                foreach (AuthorityResourceRecord authority in response.Authorities)
                                {
                                    transferResponse.Authorities.Add(authority);
                                }

                                foreach (AdditionalResourceRecord additional in response.Additionals)
                                {
                                    transferResponse.Additionals.Add(additional);
                                }

                                if (response.Answers[0].RRType == RecordType.SOA)
                                {
                                    Interlocked.Increment(ref soa);
                                }

                                if (soa != 2)
                                {
                                    continue;
                                }

                                transferResponse.Header.QdCount = (ushort)transferResponse.Questions.Count;
                                transferResponse.Header.Ancount = (ushort)transferResponse.Answers.Count;
                                transferResponse.Header.Nscount = (ushort)transferResponse.Authorities.Count;
                                transferResponse.Header.Arcount = (ushort)transferResponse.Additionals.Count;
                                transferResponse.MessageSize = messageSize;
                                return transferResponse;
                            }
                        }

                        /*next try*/
                        var message1 = string.Format(
                                    CultureInfo.InvariantCulture,
                                    ";; Connection to nameserver {0} failed",
                                    dnsServer);

                        tcpClient.Close();
                        this.Verbose(message1);
                        this.Logger.Warning((int)EventId.NetSendReceiveFail, message1);

                        this.UniqueHeaderId++;
                    }
                }
            }

            var responseMaxRetriesExcceded = new Response { Error = MaxRetriesExceededMessage };
            return responseMaxRetriesExcceded;
        }

        /// <summary>
        /// The UDP request.
        /// </summary>
        /// <param name="request">
        /// The request.
        /// </param>
        /// <returns>
        /// Various stuff.
        /// </returns>
        /// <exception cref="System.ArgumentNullException">
        /// request is null
        /// </exception>
        protected override Response UdpRequest(Request request)
        {
            if (request == null)
            {
                throw new ArgumentNullException("request");
            }

            var responseMessage = new byte[MaxSizeUdpDatagram];

            for (var intAttempts = 0; intAttempts < this.Configuration.Configuration.Retries; intAttempts++)
            {
                for (var intDnsServer = 0;
                     intDnsServer < LinqForNet20.Count(this.Configuration.Configuration.DnsServers);
                     intDnsServer++)
                {
                    var dnsServer = this.Configuration.Configuration.DnsServers[intDnsServer];

                    using (
                        var socket = new Socket(dnsServer.AddressFamily, SocketType.Dgram, ProtocolType.Udp)
                                         {
                                             SendTimeout
                                                 =
                                                 this
                                                 .Configuration
                                                 .Configuration
                                                 .DnsTimeout,
                                             ReceiveTimeout
                                                 =
                                                 this
                                                 .Configuration
                                                 .Configuration
                                                 .DnsTimeout
                                         })
                    {
                        SocketError socketError = SocketError.Success;

                        var intReceived = 0;
                        
                        var array = Enumerable.ToArray(request.Data);

                        try
                        {
                            socket.SendTo(array, dnsServer);
                        }
                        catch (SocketException exception)
                        {
                            var message = string.Format(
                                    CultureInfo.InvariantCulture,
                                    ";; Connection to nameserver {0} failed. SocketError = {1}",
                                   dnsServer,
                                   socketError);

                            this.Verbose(message);

                            this.Logger.Warning(exception, (int)EventId.NetSendReceiveFail);

                            continue; // next try
                        }
                        finally
                        {
                            this.UniqueHeaderId++;
                        }

                        try
                        {
                            intReceived = socket.Receive(
                                responseMessage, 0, responseMessage.Length, SocketFlags.None, out socketError);
                            if (socketError != SocketError.Success)
                            {
                                throw new SocketException((int)socketError);
                            }
                        }
                        catch (SocketException exception)
                        {
                            var message = string.Format(
                                    CultureInfo.InvariantCulture,
                                    ";; Connection to nameserver {0} failed after timeout of {1}ms. SocketError = {2}",
                                   dnsServer,
                                   this.Configuration.Configuration.DnsTimeout,
                                   socketError);

                            this.Verbose(message);

                            this.Logger.Warning(exception, (int)EventId.NetSendReceiveFail);

                            continue; // next try
                        }
                        finally
                        {
                            this.UniqueHeaderId++;
                        }

                        var data = new byte[intReceived];
                        Array.Copy(responseMessage, data, intReceived);
                        var response = new Response(
                            this.RecordReaderFactory, 
                            this.Configuration.Configuration.DnsServers[intDnsServer], 
                            data, 
                            intReceived);
                        if (response.Answers.Count == 0)
                        {
                            throw new SocketException((int)SocketError.HostNotFound);
                        }

                        this.AddToCache(response);
                        return response;
                    }
                }
            }

            var responseMaxTriesExceeded = new Response { Error = MaxRetriesExceededMessage };
            return responseMaxTriesExceeded;
        }

        /// <summary>
        /// The begin get host addresses local.
        /// </summary>
        /// <param name="hostNameOrAddress">
        /// The host name or address.
        /// </param>
        /// <param name="asyncCallback">
        /// The async callback.
        /// </param>
        /// <param name="state">
        /// The state.
        /// </param>
        /// <returns>
        /// The <see cref="IAsyncResult"/>.
        /// </returns>
        /// <exception cref="System.NotSupportedException">
        /// Invalid IP address.
        /// </exception>
        /// <exception cref="System.ArgumentNullException">
        /// hostNameOrAddress is null.
        /// </exception>
        private IAsyncResult BeginGetHostAddressesLocal(
            string hostNameOrAddress, AsyncCallback asyncCallback, object state)
        {
            Contract.Requires(!string.IsNullOrEmpty(hostNameOrAddress));
            Contract.Requires(asyncCallback != null);

            return this.BeginGetHostEntry(hostNameOrAddress, asyncCallback, state);
        }

        /// <summary>
        /// Begins the get host addresses local.
        /// </summary>
        /// <param name="address">
        /// The address.
        /// </param>
        /// <param name="asyncCallback">
        /// The async callback.
        /// </param>
        /// <param name="state">
        /// The state.
        /// </param>
        /// <returns>
        /// The <see cref="IAsyncResult"/>.
        /// </returns>
        /// <exception cref="System.ArgumentNullException">
        /// address is null.
        /// </exception>
        private IAsyncResult BeginGetHostAddressesLocal(IPAddress address, AsyncCallback asyncCallback, object state)
        {
            Contract.Requires(address != null);

            this.asyncEnumeratorGetHostAddressesLocal = new AsyncEnumerator<IPAddress[]>();

            return
                this.asyncEnumeratorGetHostAddressesLocal.BeginExecute(
                    this.GetHostAddressesLocalAsync(this.asyncEnumeratorGetHostAddressesLocal, address, null), 
                    asyncCallback, 
                    state);
        }

        /// <summary>
        /// Begins the get host by name local.
        /// </summary>
        /// <param name="hostName">
        /// Name of the host.
        /// </param>
        /// <param name="asyncCallback">
        /// The async callback.
        /// </param>
        /// <param name="state">
        /// The state.
        /// </param>
        /// <returns>
        /// The <see cref="IAsyncResult"/>.
        /// </returns>
        private IAsyncResult BeginGetHostByNameLocal(string hostName, AsyncCallback asyncCallback, object state)
        {
            Contract.Requires(!string.IsNullOrEmpty(hostName));

            this.asyncEnumeratorGetHostByNameLocal = new AsyncEnumerator<IPHostEntry>();

            return
                this.asyncEnumeratorGetHostByNameLocal.BeginExecute(
                    this.GetHostByNameLocalAsync(this.asyncEnumeratorGetHostByNameLocal, hostName, null), 
                    asyncCallback, 
                    state);
        }

        /// <summary>
        /// Begins the get host entry by address local.
        /// </summary>
        /// <param name="address">
        /// The address.
        /// </param>
        /// <param name="asyncCallback">
        /// The async callback.
        /// </param>
        /// <param name="state">
        /// The state.
        /// </param>
        /// <returns>
        /// the <see cref="IAsyncResult"/>.
        /// </returns>
        private IAsyncResult BeginGetHostEntryByAddressLocal(
            IPAddress address, AsyncCallback asyncCallback, object state)
        {
            Contract.Requires(address != null);
            Contract.Requires(asyncCallback != null);

            this.asyncEnumeratorGetHostEntryByAddressLocal = new AsyncEnumerator<IPHostEntry>();

            return
                this.asyncEnumeratorGetHostEntryByAddressLocal.BeginExecute(
                    this.GetHostEntryLocalAsync(this.asyncEnumeratorGetHostEntryByAddressLocal, address, null), 
                    asyncCallback, 
                    state);
        }

        /// <summary>
        /// The begin get host entry local.
        /// </summary>
        /// <param name="hostNameOrAddress">
        /// The host name or address.
        /// </param>
        /// <param name="asyncCallback">
        /// The async callback.
        /// </param>
        /// <param name="state">
        /// The state.
        /// </param>
        /// <returns>
        /// The <see cref="IAsyncResult"/>.
        /// </returns>
        /// <exception cref="System.ArgumentNullException">
        /// hostNameOrAddress is null
        /// </exception>
        private IAsyncResult BeginGetHostEntryByHostNameOrAddressLocal(
            string hostNameOrAddress, AsyncCallback asyncCallback, object state)
        {
            Contract.Requires(!string.IsNullOrEmpty(hostNameOrAddress));

            this.asyncEnumeratorGetHostEntryByHostNameLocal = new AsyncEnumerator<IPHostEntry>();

            return
                this.asyncEnumeratorGetHostEntryByHostNameLocal.BeginExecute(
                    this.GetHostEntryLocalAsync(
                        this.asyncEnumeratorGetHostEntryByHostNameLocal, hostNameOrAddress, null), 
                    asyncCallback, 
                    state);
        }

        /// <summary>
        /// Begins the get host entry local.
        /// </summary>
        /// <param name="address">
        /// The address.
        /// </param>
        /// <param name="asyncCallback">
        /// The async callback.
        /// </param>
        /// <param name="state">
        /// The state.
        /// </param>
        /// <returns>
        /// The <see cref="IAsyncResult"/>.
        /// </returns>
        /// <exception cref="System.ArgumentNullException">
        /// address is null.
        /// </exception>
        private IAsyncResult BeginGetHostEntryLocal(IPAddress address, AsyncCallback asyncCallback, object state)
        {
            Contract.Requires(address != null);
            Contract.Requires(asyncCallback != null);

            this.asyncEnumeratorGetHostEntryByAddressLocal = new AsyncEnumerator<IPHostEntry>();

            return
                this.asyncEnumeratorGetHostEntryByAddressLocal.BeginExecute(
                    this.GetHostEntryLocalAsync(this.asyncEnumeratorGetHostEntryByAddressLocal, address, null), 
                    asyncCallback, 
                    state);
        }

        /// <summary>
        /// Begins the get response local.
        /// </summary>
        /// <param name="request">
        /// The request.
        /// </param>
        /// <param name="asyncCallback">
        /// The async callback.
        /// </param>
        /// <param name="state">
        /// The state.
        /// </param>
        /// <returns>
        /// The <see cref="IAsyncResult"/>.
        /// </returns>
        /// <exception cref="System.ArgumentNullException">
        /// request is null.
        /// </exception>
        /// <exception cref="System.NotSupportedException">
        /// Configurations of UDP or TCP only supported.
        /// </exception>
        private IAsyncResult BeginGetResponseLocal(Request request, AsyncCallback asyncCallback, object state)
        {
            Contract.Requires(request != null);

            if (this.Configuration.Configuration.TransportType != TransportType.Tcp
                && this.Configuration.Configuration.TransportType != TransportType.Udp)
            {
                throw new NotSupportedException("Configurations of UDP or TCP only supported");
            }

            this.asyncEnumeratorGetResponseLocal = new AsyncEnumerator<Response>();

            return
                this.asyncEnumeratorGetResponseLocal.BeginExecute(
                    this.GetResponseLocalAsync(this.asyncEnumeratorGetResponseLocal, request, null), 
                    asyncCallback, 
                    state);
        }

        /// <summary>
        /// Begins the make entry local.
        /// </summary>
        /// <param name="hostName">
        /// Name of the host.
        /// </param>
        /// <param name="asyncCallback">
        /// The async callback.
        /// </param>
        /// <param name="state">
        /// The state.
        /// </param>
        /// <returns>
        /// The <see cref="IAsyncResult"/>.
        /// </returns>
        /// <exception cref="System.ArgumentNullException">
        /// hostName is null
        /// </exception>
        private IAsyncResult BeginMakeEntryLocal(string hostName, AsyncCallback asyncCallback, object state)
        {
            Contract.Requires(!string.IsNullOrEmpty(hostName));

            Contract.Requires(asyncCallback != null);

            this.asyncEnumeratorMakeEntryLocal = new AsyncEnumerator<IPHostEntry>();

            return
                this.asyncEnumeratorMakeEntryLocal.BeginExecute(
                    this.MakeEntryLocalAsync(this.asyncEnumeratorMakeEntryLocal, hostName, null), asyncCallback, state);
        }

        /// <summary>
        /// Begins the query local.
        /// </summary>
        /// <param name="name">
        /// The name.
        /// </param>
        /// <param name="queryType">
        /// Type of the query.
        /// </param>
        /// <param name="queryClassType">
        /// Type of the query class.
        /// </param>
        /// <param name="asyncCallback">
        /// The async callback.
        /// </param>
        /// <param name="state">
        /// The state.
        /// </param>
        /// <returns>
        /// The <see cref="IAsyncResult"/>.
        /// </returns>
        /// <exception cref="System.ArgumentNullException">
        /// name is null
        /// </exception>
        private IAsyncResult BeginQueryLocal(
            string name, QType queryType, QClassType queryClassType, AsyncCallback asyncCallback, object state)
        {
            Contract.Requires(!string.IsNullOrEmpty(name));

            this.asyncEnumeratorQueryLocal = new AsyncEnumerator<Response>();

            return
                this.asyncEnumeratorQueryLocal.BeginExecute(
                    this.GetQueryLocalAsync(this.asyncEnumeratorQueryLocal, name, queryType, queryClassType, null), 
                    asyncCallback, 
                    state);
        }

        /// <summary>
        /// The begin resolve local.
        /// </summary>
        /// <param name="hostName">
        /// The host name.
        /// </param>
        /// <param name="asyncCallback">
        /// The async callback.
        /// </param>
        /// <param name="state">
        /// The state.
        /// </param>
        /// <returns>
        /// The <see cref="IAsyncResult"/>.
        /// </returns>
        /// <exception cref="System.ArgumentNullException">
        /// hostName is null
        /// </exception>
        private IAsyncResult BeginResolveLocal(string hostName, AsyncCallback asyncCallback, object state)
        {
            Contract.Requires(!string.IsNullOrEmpty(hostName));

            this.asyncEnumeratorResolveLocal = new AsyncEnumerator<IPHostEntry>();

            return
                this.asyncEnumeratorResolveLocal.BeginExecute(
                    this.ResolveLocalAsync(this.asyncEnumeratorResolveLocal, hostName, null), asyncCallback, state);
        }

        /// <summary>
        /// Releases unmanaged and - optionally - managed resources
        /// </summary>
        /// <param name="disposing">
        /// <c>true</c> to release both managed and unmanaged resources; <c>false</c> to release only unmanaged resources.
        /// </param>
        private void Dispose(bool disposing)
        {
            if (this.disposed)
            {
                return;
            }

            if (disposing)
            {
                // clean up managed resources
                if (this.oneManyResourceLockConfiguration != null)
                {
                    this.oneManyResourceLockConfiguration.Dispose();
                }

                if (this.oneManyResourceLockUniqueHeaderId != null)
                {
                    this.oneManyResourceLockUniqueHeaderId.Dispose();
                }

                this.oneManyResourceLockConfiguration = null;
                this.oneManyResourceLockUniqueHeaderId = null;

                configurationLocal = null;
            }

            this.disposed = true;
        }

        /// <summary>
        /// The end get host addresses local.
        /// </summary>
        /// <param name="asyncResult">
        /// The async result.
        /// </param>
        /// <returns>
        /// The <see cref="IPAddress[]"/>.
        /// </returns>
        /// <exception cref="System.ArgumentNullException">
        /// asyncResult is null
        /// </exception>
        private IPAddress[] EndGetHostAddressesLocal(IAsyncResult asyncResult)
        {
            Contract.Requires(asyncResult != null);

            var entry = this.asyncEnumeratorGetHostAddressesLocal.EndExecute(asyncResult);

            return entry;
        }

        /// <summary>
        /// Ends the get host by name local.
        /// </summary>
        /// <param name="asyncResult">
        /// The async result.
        /// </param>
        /// <returns>
        /// The <see cref="IPHostEntry"/>.
        /// </returns>
        private IPHostEntry EndGetHostByNameLocal(IAsyncResult asyncResult)
        {
            Contract.Requires(asyncResult != null);

            var entry = this.asyncEnumeratorGetHostByNameLocal.EndExecute(asyncResult);

            return entry;
        }

        /// <summary>
        /// Ends the get host entry by address local.
        /// </summary>
        /// <param name="asyncResult">
        /// The async result.
        /// </param>
        /// <returns>
        /// The <see cref="IPHostEntry"/>.
        /// </returns>
        private IPHostEntry EndGetHostEntryByAddressLocal(IAsyncResult asyncResult)
        {
            Contract.Requires(asyncResult != null);

            var entry = this.asyncEnumeratorGetHostEntryByAddressLocal.EndExecute(asyncResult);

            return entry;
        }

        /// <summary>
        /// The end get host entry local.
        /// </summary>
        /// <param name="asyncResult">
        /// The async result.
        /// </param>
        /// <returns>
        /// The <see cref="IPHostEntry"/>.
        /// </returns>
        /// <exception cref="System.ArgumentNullException">
        /// asyncResult is null
        /// </exception>
        private IPHostEntry EndGetHostEntryByHostNameLocal(IAsyncResult asyncResult)
        {
            Contract.Requires(asyncResult != null);

            var entry = this.asyncEnumeratorGetHostEntryByHostNameLocal.EndExecute(asyncResult);

            return entry;
        }

        /// <summary>
        /// Ends the get response.
        /// </summary>
        /// <param name="asyncResult">
        /// The async result.
        /// </param>
        /// <returns>
        /// The <see cref="Response"/>.
        /// </returns>
        /// <exception cref="System.ArgumentNullException">
        /// asyncResult is null
        /// </exception>
        private Response EndGetResponseLocal(IAsyncResult asyncResult)
        {
            Contract.Requires(asyncResult != null);

            var response = this.asyncEnumeratorGetResponseLocal.EndExecute(asyncResult);

            return response;
        }

        /// <summary>
        /// Ends the make entry local.
        /// </summary>
        /// <param name="asyncResult">
        /// The async result.
        /// </param>
        /// <returns>
        /// The <see cref="IPHostEntry"/>.
        /// </returns>
        /// <exception cref="System.ArgumentNullException">
        /// asyncResult is null
        /// </exception>
        private IPHostEntry EndMakeEntryLocal(IAsyncResult asyncResult)
        {
            Contract.Requires(asyncResult != null);

            return this.asyncEnumeratorMakeEntryLocal.EndExecute(asyncResult);
        }

        /// <summary>
        /// The end query local.
        /// </summary>
        /// <param name="asyncResult">
        /// The async result.
        /// </param>
        /// <returns>
        /// The <see cref="Response"/>.
        /// </returns>
        /// <exception cref="System.ArgumentNullException">
        /// asyncResult is null
        /// </exception>
        private Response EndQueryLocal(IAsyncResult asyncResult)
        {
            Contract.Requires(asyncResult != null);

            var result = this.asyncEnumeratorQueryLocal.EndExecute(asyncResult);

            return result;
        }

        /// <summary>
        /// The end resolve local.
        /// </summary>
        /// <param name="asyncResult">
        /// The async result.
        /// </param>
        /// <returns>
        /// The <see cref="IPHostEntry"/>.
        /// </returns>
        /// <exception cref="System.ArgumentNullException">
        /// asyncResult is null.
        /// </exception>
        private IPHostEntry EndResolveLocal(IAsyncResult asyncResult)
        {
            Contract.Requires(asyncResult != null);

            var result = this.asyncEnumeratorResolveLocal.EndExecute(asyncResult);

            return result;
        }

        /// <summary>
        /// Gets the host addresses local async.
        /// </summary>
        /// <param name="asyncEnumerator">
        /// The async enumerator.
        /// </param>
        /// <param name="address">
        /// The address.
        /// </param>
        /// <param name="cancellationToken">
        /// The cancellation token.
        /// </param>
        /// <returns>
        /// The <see cref="IEnumerator"/>.
        /// </returns>
        private IEnumerator<int> GetHostAddressesLocalAsync(
            AsyncEnumerator<IPAddress[]> asyncEnumerator, IPAddress address, CancellationToken cancellationToken)
        {
            Contract.Requires(asyncEnumerator != null);
            Contract.Requires(address != null);

            this.BeginGetHostEntryLocal(address, asyncEnumerator.End(), null);

            yield return 1;

            var entry = this.EndGetHostEntryByAddressLocal(asyncEnumerator.DequeueAsyncResult());

            asyncEnumerator.Result = entry.AddressList;
        }

        /// <summary>
        /// Gets the host by name local async.
        /// </summary>
        /// <param name="asyncEnumerator">
        /// The async enumerator.
        /// </param>
        /// <param name="hostName">
        /// Name of the host.
        /// </param>
        /// <param name="cancellationToken">
        /// The cancellation token.
        /// </param>
        /// <returns>
        /// The <see cref="IEnumerator"/>.
        /// </returns>
        private IEnumerator<int> GetHostByNameLocalAsync(
            AsyncEnumerator<IPHostEntry> asyncEnumerator, string hostName, CancellationToken cancellationToken)
        {
            Contract.Requires(asyncEnumerator != null);
            Contract.Requires(!string.IsNullOrEmpty(hostName));

            this.BeginMakeEntryLocal(hostName, asyncEnumerator.End(), null);

            yield return 1;

            var entry = this.EndMakeEntryLocal(asyncEnumerator.DequeueAsyncResult());

            asyncEnumerator.Result = entry;
        }

        /// <summary>
        /// Gets the host entry local async.
        /// </summary>
        /// <param name="asyncEnumerator">
        /// The async enumerator.
        /// </param>
        /// <param name="hostNameOrAddress">
        /// The host name or address.
        /// </param>
        /// <param name="cancellationToken">
        /// The cancellation token.
        /// </param>
        /// <returns>
        /// The <see cref="IEnumerator"/>.
        /// </returns>
        private IEnumerator<int> GetHostEntryLocalAsync(
            AsyncEnumerator<IPHostEntry> asyncEnumerator, string hostNameOrAddress, CancellationToken cancellationToken)
        {
            Contract.Requires(asyncEnumerator != null);
            Contract.Requires(!string.IsNullOrEmpty(hostNameOrAddress));

            IPAddress address;
            if (IPAddress.TryParse(hostNameOrAddress, out address))
            {
                this.BeginGetHostEntryLocal(address, asyncEnumerator.End(), null);

                yield return 1;

                var entry = this.EndGetHostEntryByHostNameLocal(asyncEnumerator.DequeueAsyncResult());

                asyncEnumerator.Result = entry;
            }
            else
            {
                this.BeginMakeEntryLocal(hostNameOrAddress, asyncEnumerator.End(), null);

                yield return 1;

                var entryLocal = this.EndMakeEntryLocal(asyncEnumerator.DequeueAsyncResult());

                asyncEnumerator.Result = entryLocal;
            }
        }

        /// <summary>
        /// Gets the host entry local async.
        /// </summary>
        /// <param name="asyncEnumerator">
        /// The async enumerator.
        /// </param>
        /// <param name="address">
        /// The address.
        /// </param>
        /// <param name="cancellationToken">
        /// The cancellation token.
        /// </param>
        /// <returns>
        /// The <see cref="IEnumerator"/>.
        /// </returns>
        private IEnumerator<int> GetHostEntryLocalAsync(
            AsyncEnumerator<IPHostEntry> asyncEnumerator, IPAddress address, CancellationToken cancellationToken)
        {
            Contract.Requires(asyncEnumerator != null);
            Contract.Requires(address != null);

            this.BeginQueryLocal(this.GetArpaFromIp(address), QType.PTR, QClassType.IN, asyncEnumerator.End(), null);

            yield return 1;

            var response = this.EndQueryLocal(asyncEnumerator.DequeueAsyncResult());

            if (response.RecordsPtr.Count > 0)
            {
                this.BeginMakeEntryLocal(response.RecordsPtr[0].PtrdName, asyncEnumerator.End(), null);

                yield return 1;

                var entry = this.EndMakeEntryLocal(asyncEnumerator.DequeueAsyncResult());

                asyncEnumerator.Result = entry;
            }
            else
            {
                this.Logger.Warning(
                    (int)EventId.NetSendReceiveFail, 
                    "ResolverDefault.GetHostEntryLocalAsync(): No response.RecordsPtr records found. Returning new 'IPHostEntry()'");
                asyncEnumerator.Result = new IPHostEntry();
            }
        }

        /// <summary>
        /// Gets the query local async.
        /// </summary>
        /// <param name="asyncEnumerator">
        /// The async enumerator.
        /// </param>
        /// <param name="name">
        /// The name.
        /// </param>
        /// <param name="queryType">
        /// Type of the query.
        /// </param>
        /// <param name="queryClassType">
        /// Type of the query class.
        /// </param>
        /// <param name="cancellationToken">
        /// The cancellation token.
        /// </param>
        /// <returns>
        /// The <see cref="IEnumerator"/>.
        /// </returns>
        private IEnumerator<int> GetQueryLocalAsync(
            AsyncEnumerator<Response> asyncEnumerator, 
            string name, 
            QType queryType, 
            QClassType queryClassType, 
            CancellationToken cancellationToken)
        {
            Contract.Requires(asyncEnumerator != null);
            Contract.Requires(!string.IsNullOrEmpty(name));

            this.InitializeUniqueHeaderId();

            Question question = null;

            if (queryType == QType.PTR)
            {
                IPAddress tryAddress;
                if (IPAddress.TryParse(name, out tryAddress))
                {
                    var arpaFromIp = this.GetArpaFromIp(tryAddress);
                    question = new Question(arpaFromIp, queryClassType, queryType);
                }
                else
                {
                    question = new Question(name, queryClassType, queryType);
                }
            }
            else
            {
                question = new Question(name, queryClassType, queryType);
            }
            
            var response = this.SearchInCache(question);

            if (response != null)
            {
                asyncEnumerator.Result = response;

                yield break;
            }

            var request = new Request();
            request.AddQuestion(question);

            this.BeginGetResponseLocal(request, asyncEnumerator.End(), null);

            yield return 1;

            var responseLocal = this.EndGetResponseLocal(asyncEnumerator.DequeueAsyncResult());

            asyncEnumerator.Result = responseLocal;
        }

        /// <summary>
        /// Gets the response local async.
        /// </summary>
        /// <param name="asyncEnumerator">
        /// The async enumerator.
        /// </param>
        /// <param name="request">
        /// The request.
        /// </param>
        /// <param name="cancellationToken">
        /// The cancellation token.
        /// </param>
        /// <returns>
        /// The <see cref="IEnumerator"/>.
        /// </returns>
        private IEnumerator<int> GetResponseLocalAsync(
            AsyncEnumerator<Response> asyncEnumerator, Request request, CancellationToken cancellationToken)
        {
            Contract.Requires(asyncEnumerator != null);
            Contract.Requires(request != null);

            request.Header.Id = (ushort)this.UniqueHeaderId;
            request.Header.RecursionDesired = this.Configuration.Configuration.UseRecursion;

            if (this.Configuration.Configuration.TransportType == TransportType.Udp)
            {
                this.BeginGetUdpRequest(request, asyncEnumerator.End(), null);

                yield return 1;

                var udpResponse = this.EndGetUdpRequest(asyncEnumerator.DequeueAsyncResult());

                asyncEnumerator.Result = udpResponse;
            }

            if (this.Configuration.Configuration.TransportType == TransportType.Tcp)
            {
                this.BeginGetTcpRequest(request, asyncEnumerator.End(), null);

                yield return 1;

                var tcpResponse = this.EndGetTcpRequest(asyncEnumerator.DequeueAsyncResult());

                asyncEnumerator.Result = tcpResponse;
            }
        }

        /// <summary>
        /// The get TCP request async.
        /// </summary>
        /// <param name="asyncEnumerator">
        /// The async enumerator.
        /// </param>
        /// <param name="request">
        /// The request.
        /// </param>
        /// <param name="dnsServers">
        /// The dns servers.
        /// </param>
        /// <param name="retries">
        /// The retries.
        /// </param>
        /// <param name="cancellationToken">
        /// The cancellation token.
        /// </param>
        /// <returns>
        /// The <see cref="IEnumerator"/>.
        /// </returns>
        private IEnumerator<int> GetTcpRequestLocalAsync(
            AsyncEnumerator<Response> asyncEnumerator, 
            Request request, 
            IList<IPEndPoint> dnsServers, 
            int retries, 
            CancellationToken cancellationToken)
        {
            Contract.Requires(request != null);
            Contract.Requires(dnsServers != null);
            Contract.Requires(dnsServers.Count > 0);
            Contract.Requires(retries > 0);

            var currentRetryCount = 0;

            var currentDnsServerIndex = 0;

            if (cancellationToken != null)
            {
                asyncEnumerator.Cancel(new CancellationToken { CancellationReason = CancellationReason.UserCancelled });
            }
            else
            {
                asyncEnumerator.SetCancelTimeout(
                    this.Configuration.Configuration.DnsTimeout, 
                    new CancellationToken { CancellationReason = CancellationReason.Timeout });
            }

            while (currentRetryCount < retries)
            {
                var currentDnsServer = dnsServers[currentDnsServerIndex];

                using (var tcpClient = new TcpClient(currentDnsServer.AddressFamily)
                                           {
                                               ReceiveTimeout = this.Configuration.Configuration.DnsTimeout
                                           })
                {
                    try
                    {
                        tcpClient.BeginConnect(
                            currentDnsServer.Address, currentDnsServer.Port, asyncEnumerator.End(), null);
                    }
                    catch (SocketException exception)
                    {
                        var message = string.Format(
                                    CultureInfo.InvariantCulture,
                                    ";; Connection to nameserver {0} failed after timeout of {1}ms.",
                                   currentDnsServer,
                                   this.Configuration.Configuration.DnsTimeout);

                        this.Verbose(message);

                        this.Logger.Warning(exception, (int)EventId.NetConnectFail);

                        /*Increment unique header id*/
                        this.UniqueHeaderId++;

                        /*Increment retry count*/
                        Interlocked.Increment(ref currentRetryCount);

                        /*Next attempt*/
                        continue;
                    }

                    /*Async enumerator await*/
                    yield return 1;

                    try
                    {
                        tcpClient.EndConnect(asyncEnumerator.DequeueAsyncResult());
                    }
                    catch (Exception exception)
                    {
                        var message = string.Format(
                                CultureInfo.InvariantCulture, ";; Connection to nameserver {0} failed", currentDnsServer);

                        this.Verbose(message);

                        this.Logger.Warning(exception, (int)EventId.NetConnectFail);

                        /*Increment unique header id*/
                        this.UniqueHeaderId++;

                        /*Increment retry count*/
                        Interlocked.Increment(ref currentRetryCount);

                        /*Next attempt*/
                        continue;
                    }

                    object cancelvalue;

                    var isCanceled = asyncEnumerator.IsCanceled(out cancelvalue);

                    var token = cancelvalue as CancellationToken;

                    if (isCanceled)
                    {
                        if (token != null && token.GetType() == typeof(CancellationToken))
                        {
                            if (token.CancellationReason == CancellationReason.Timeout)
                            {
                                var msg = string.Format(
                                    CultureInfo.InvariantCulture, 
                                    ";; Connection to nameserver {0} failed. REASON: Operation timed out", 
                                    currentDnsServer);

                                this.Logger.Warning((int)EventId.NetConnectTimeout, msg);

                                this.Verbose(msg);

                                /*Increment unique header id*/
                                this.UniqueHeaderId++;

                                /*Increment retry count*/
                                Interlocked.Increment(ref currentRetryCount);

                                /*Next attempt*/
                                continue;
                            }

                            if (token.CancellationReason == CancellationReason.UserCancelled)
                            {
                                var msg = string.Format(
                                    CultureInfo.InvariantCulture, 
                                    ";; Connection to nameserver {0} failed. REASON: Operation cancelled by user", 
                                    currentDnsServer);

                                this.Logger.Warning((int)EventId.UserTaskCancellation, msg);

                                this.Verbose(msg);

                                asyncEnumerator.Result = new Response { Error = msg };

                                yield break;
                            }
                        }
                    }

                    using (var bufferedStream = new BufferedStream(tcpClient.GetStream()))
                    {
                        var data = request.Data;

                        var bytes = new List<byte>();
                        foreach (var b in data)
                        {
                            bytes.Add(b);
                        }

                        var byteArray = bytes.ToArray();

                        bufferedStream.WriteByte((byte)((byteArray.Length >> 8) & 0xff));
                        bufferedStream.WriteByte((byte)(byteArray.Length & 0xff));

                        try
                        {
                            bufferedStream.BeginWrite(byteArray, 0, byteArray.Length, asyncEnumerator.End(), null);
                        }
                        catch (Exception exception)
                        {
                            var message = string.Format(
                                CultureInfo.InvariantCulture, ";; Data send to nameserver {0} failed. Please consult error logs for more detail.", currentDnsServer);

                            this.Verbose(message);

                            this.Logger.Warning(exception, (int)EventId.NetSendReceiveFail);

                            /*Increment unique header id*/
                            this.UniqueHeaderId++;

                            /*Increment retry count*/
                            Interlocked.Increment(ref currentRetryCount);

                            /*Next attempt*/
                            continue;
                        }

                        yield return 1;

                        try
                        {
                            bufferedStream.EndWrite(asyncEnumerator.DequeueAsyncResult());
                        }
                        catch (Exception exception)
                        {
                            var message = string.Format(
                                CultureInfo.InvariantCulture, ";; Data send to nameserver {0} failed. Please consult error logs for more detail.", currentDnsServer);

                            this.Verbose(message);

                            this.Logger.Warning(exception, (int)EventId.NetSendReceiveFail);

                            /*Increment unique header id*/
                            this.UniqueHeaderId++;

                            /*Increment retry count*/
                            Interlocked.Increment(ref currentRetryCount);

                            /*Next attempt*/
                            continue;
                        }

                        try
                        {
                            bufferedStream.Flush();
                        }
                        catch (IOException exception)
                        {
                            var message = string.Format(
                                CultureInfo.InvariantCulture, ";; Data buffer to nameserver {0} failed. Please consult error logs for more detail.", currentDnsServer);

                            this.Verbose(message);

                            this.Logger.Warning(exception, (int)EventId.NetSendReceiveFail);

                            /*Increment unique header id*/
                            this.UniqueHeaderId++;

                            /*Increment retry count*/
                            Interlocked.Increment(ref currentRetryCount);

                            /*Next attempt*/
                            continue;
                        }

                        var transferResponse = new Response();
                        var soa = 0;
                        var messageSize = 0;

                        while (true)
                        {
                            var length = bufferedStream.ReadByte() << 8 | bufferedStream.ReadByte();

                            /*Connection to DNS server failed*/
                            if (length <= 0)
                            {
                                var msg = string.Format(
                                    CultureInfo.InvariantCulture, 
                                    ";; Connection to nameserver {0} failed", 
                                    currentDnsServer);

                                this.Logger.Warning((int)EventId.NetConnectFail, msg);

                                this.Verbose(msg);

                                /*Next DNS server*/
                                Interlocked.Increment(ref currentDnsServerIndex);

                                /*Reset retry count*/
                                Interlocked.Exchange(ref currentRetryCount, 0);

                                /*Increment unique header id*/
                                this.UniqueHeaderId++;

                                /*Continue with next DNS server*/
                                continue; 
                            }

                            messageSize += length;

                            byteArray = new byte[length];

                            try
                            {
                                bufferedStream.BeginRead(byteArray, 0, length, asyncEnumerator.End(), null);
                            }
                            catch (Exception exception)
                            {
                                var msg = string.Format(
                                    CultureInfo.InvariantCulture,
                                    ";; Data read on nameserver {0} failed. Please see error logs for more details.",
                                    currentDnsServer);

                                this.Verbose(msg);

                                this.Logger.Warning(exception, (int)EventId.NetSendReceiveFail);

                                /*Reset retry count*/
                                Interlocked.Exchange(ref currentRetryCount, 0);

                                /*Increment unique header id*/
                                this.UniqueHeaderId++;

                                continue; /*Continue with next DNS server*/
                            }

                            yield return 1;

                            try
                            {
                                bufferedStream.EndRead(asyncEnumerator.DequeueAsyncResult());
                            }
                            catch (Exception exception)
                            {
                                var msg = string.Format(
                                    CultureInfo.InvariantCulture,
                                    ";; Data read on nameserver {0} failed. Please see error logs for more details.",
                                    currentDnsServer);

                                this.Verbose(msg);

                                this.Logger.Warning(exception, (int)EventId.NetSendReceiveFail);

                                /*Reset retry count*/
                                Interlocked.Exchange(ref currentRetryCount, 0);

                                /*Increment unique header id*/
                                this.UniqueHeaderId++;

                                continue; /*Continue with next DNS server*/
                            }

                            var response = new Response(this.RecordReaderFactory, currentDnsServer, byteArray, length);

                            if (response.Answers.Count == 0)
                            {
                                throw new SocketException((int)SocketError.HostNotFound);
                            }

                            if (response.Header.ResponseCode != RCodeType.NoError)
                            {
                                asyncEnumerator.Result = response;

                                yield break;
                            }

                            if (response.Questions[0].QType != QType.AXFR)
                            {
                                this.AddToCache(response);
                                asyncEnumerator.Result = response;

                                yield break;
                            }

                            // Zone transfer
                            if (transferResponse.Questions.Count == 0)
                            {
                                foreach (Question question in response.Questions)
                                {
                                    transferResponse.Questions.Add(question);
                                }
                            }

                            foreach (AnswerResourceRecord answer in response.Answers)
                            {
                                transferResponse.Answers.Add(answer);
                            }

                            foreach (AuthorityResourceRecord authority in response.Authorities)
                            {
                                transferResponse.Authorities.Add(authority);
                            }

                            foreach (AdditionalResourceRecord additional in response.Additionals)
                            {
                                transferResponse.Additionals.Add(additional);
                            }

                            if (response.Answers[0].RRType == RecordType.SOA)
                            {
                                Interlocked.Increment(ref soa);
                            }

                            if (soa == 2)
                            {
                                transferResponse.Header.QdCount = (ushort)transferResponse.Questions.Count;
                                transferResponse.Header.Ancount = (ushort)transferResponse.Answers.Count;
                                transferResponse.Header.Nscount = (ushort)transferResponse.Authorities.Count;
                                transferResponse.Header.Arcount = (ushort)transferResponse.Additionals.Count;
                                transferResponse.MessageSize = messageSize;

                                asyncEnumerator.Result = transferResponse;

                                yield break;
                            }

                            /*Increment unique header id*/
                            this.UniqueHeaderId++;
                        }
                    }
                }
            }

            var responseMaxRetriesExceeded = new Response { Error = MaxRetriesExceededMessage };
            asyncEnumerator.Result = responseMaxRetriesExceeded;
        }

        /// <summary>
        /// The get UDP request async.
        /// </summary>
        /// <param name="asyncEnumerator">
        /// The async enumerator.
        /// </param>
        /// <param name="request">
        /// The request.
        /// </param>
        /// <param name="dnsServers">
        /// The DNS servers.
        /// </param>
        /// <param name="retries">
        /// The retries.
        /// </param>
        /// <param name="cancellationToken">
        /// The cancellation token.
        /// </param>
        /// <returns>
        /// The <see cref="IEnumerator"/>.
        /// </returns>
        private IEnumerator<int> GetUdpRequestLocalAsync(
            AsyncEnumerator<Response> asyncEnumerator, 
            Request request, 
            IList<IPEndPoint> dnsServers, 
            int retries, 
            CancellationToken cancellationToken)
        {
            Contract.Requires(request != null);
            Contract.Requires(dnsServers != null);
            Contract.Requires(dnsServers.Count > 0);
            Contract.Requires(retries > 0);

            var responseMessage = new byte[MaxSizeUdpDatagram];

            var currentRetryCount = 0;

            var currentDnsServerIndex = 0;
            
            while (currentRetryCount < retries)
            {
                var currentDnsServer = dnsServers[currentDnsServerIndex];

                using (var socket = new Socket(currentDnsServer.AddressFamily, SocketType.Dgram, ProtocolType.Udp))
                {
                    socket.SetSocketOption(
                        SocketOptionLevel.Socket, 
                        SocketOptionName.ReceiveTimeout, 
                        this.Configuration.Configuration.DnsTimeout);

                    var array = Enumerable.ToArray(request.Data);

                    try
                    {
                        socket.BeginSendTo(
                            array, 0, array.Length, SocketFlags.None, currentDnsServer, asyncEnumerator.End(), null);
                    }
                    catch (Exception exception)
                    {
                        var message = string.Format(
                                    CultureInfo.InvariantCulture,
                                    ";; Connection to nameserver {0} failed after timeout of {1}ms.",
                                   currentDnsServer,
                                   this.Configuration.Configuration.DnsTimeout);

                        this.Verbose(message);

                        this.Logger.Warning(exception, (int)EventId.NetSendReceiveFail);

                        /*Increment unique header id*/
                        this.UniqueHeaderId++;

                        /*Increment retry count*/
                        Interlocked.Increment(ref currentRetryCount);

                        /*Next attempt*/
                        continue;
                    }

                    /*Async enumerator await*/
                    yield return 1;

                    try
                    {
                        socket.EndSendTo(asyncEnumerator.DequeueAsyncResult());
                    }
                    catch (Exception exception)
                    {
                        var message = string.Format(
                                CultureInfo.InvariantCulture, ";; Connection to nameserver {0} failed", currentDnsServer);

                        this.Verbose(message);

                        this.Logger.Warning(exception, (int)EventId.NetSendReceiveFail);

                        /*Increment retry count*/
                        Interlocked.Increment(ref currentRetryCount);

                        /*Increment unique header id*/
                        this.UniqueHeaderId++;

                        /*Next attempt*/
                        continue;
                    }

                    object cancelvalue;

                    var isCanceled = asyncEnumerator.IsCanceled(out cancelvalue);

                    var token = cancelvalue as CancellationToken;

                    if (isCanceled)
                    {
                        if (token != null && token.GetType() == typeof(CancellationToken))
                        {
                            if (token.CancellationReason == CancellationReason.Timeout)
                            {
                                var msg = string.Format(
                                    CultureInfo.InvariantCulture, 
                                    ";; Connection to nameserver {0} failed. REASON: Operation timed out", 
                                    currentDnsServer);

                                this.Logger.Warning((int)EventId.NetConnectTimeout, msg);

                                this.Verbose(msg);

                                /*Increment unique header id*/
                                this.UniqueHeaderId++;

                                Interlocked.Increment(ref currentRetryCount);
                                continue; /*Next attempt*/
                            }

                            if (token.CancellationReason == CancellationReason.UserCancelled)
                            {
                                var msg = string.Format(
                                    CultureInfo.InvariantCulture, 
                                    ";; Connection to nameserver {0} failed. REASON: Operation cancelled by user", 
                                    currentDnsServer);

                                this.Logger.Warning((int)EventId.UserTaskCancellation, msg);

                                this.Verbose(msg);

                                asyncEnumerator.Result = new Response { Error = msg };

                                yield break;
                            }
                        }
                    }

                    SocketError socketError = SocketError.Success;
                    try
                    {
                        socket.BeginReceive(
                            responseMessage, 
                            0, 
                            MaxSizeUdpDatagram, 
                            SocketFlags.None, 
                            out socketError, 
                            asyncEnumerator.End(), 
                            null);

                        if (socketError != SocketError.Success)
                        {
                            throw new SocketException((int)socketError);
                        }
                    }
                    catch (Exception exception)
                    {
                        var msg = string.Format(
                                    CultureInfo.InvariantCulture,
                                    ";; Data read on nameserver {0} failed with exception code '{1}'. Please see error logs for more details.",
                                    currentDnsServer, 
                                    socketError);

                        this.Verbose(msg);

                        this.Logger.Warning(exception, (int)EventId.NetSendReceiveFail);
                        
                        /*Increment unique header id*/
                        this.UniqueHeaderId++;

                        /*Next DNS server*/
                        Interlocked.Increment(ref currentDnsServerIndex);

                        /*Reset retry count*/
                        Interlocked.Exchange(ref currentRetryCount, 0);

                        /*Next attempt*/
                        continue;
                    }

                    /*Async enumerator await*/
                    yield return 1;

                    int received;

                    try
                    {
                        received = socket.EndReceive(asyncEnumerator.DequeueAsyncResult());
                    }
                    catch (Exception exception)
                    {
                        var msg = string.Format(
                                    CultureInfo.InvariantCulture,
                                    ";; Data read on nameserver {0} failed. Please see error logs for more details.",
                                    currentDnsServer);

                        this.Verbose(msg);

                        this.Logger.Warning(exception, (int)EventId.NetSendReceiveFail);
                        
                        /*Next DNS server*/
                        Interlocked.Increment(ref currentDnsServerIndex);

                        /*Reset retry count*/
                        Interlocked.Exchange(ref currentRetryCount, 0);

                        /*Increment unique header id*/
                        this.UniqueHeaderId++;

                        /*Next attempt*/
                        continue;
                    }

                    var data = new byte[received];

                    Array.Copy(responseMessage, data, received);

                    var response = new Response(this.RecordReaderFactory, currentDnsServer, data, received);

                    if (response.Answers.Count == 0)
                    {
                        throw new SocketException((int)SocketError.HostNotFound);
                    }

                    this.AddToCache(response);

                    asyncEnumerator.Result = response;

                    yield break;
                }
            }

            var responseMaxRetriesExceeded = new Response { Error = MaxRetriesExceededMessage };
            asyncEnumerator.Result = responseMaxRetriesExceeded;
        }

        /// <summary>
        /// Makes the entry async.
        /// </summary>
        /// <param name="asyncEnumerator">
        /// The async enumerator.
        /// </param>
        /// <param name="hostName">
        /// Name of the host.
        /// </param>
        /// <param name="cancellationToken">
        /// The cancellation token.
        /// </param>
        /// <returns>
        /// the <see cref="IEnumerator"/>.
        /// </returns>
        private IEnumerator<int> MakeEntryLocalAsync(
            AsyncEnumerator<IPHostEntry> asyncEnumerator, string hostName, CancellationToken cancellationToken)
        {
            Contract.Requires(asyncEnumerator != null);
            Contract.Requires(!string.IsNullOrEmpty(hostName));

            this.InitializeUniqueHeaderId();

            Response responsesInterNetwork;
            Response responsesInterNetworkV6 = null;

            var entry = new IPHostEntry { HostName = hostName };

            try
            {
                this.BeginQueryLocal(hostName, QType.A, QClassType.IN, asyncEnumerator.End(), null);
            }
            catch (Exception exception)
            {
                this.Logger.Error(exception, (int)EventId.NetSendReceiveFail);
            }

            yield return 1;

            try
            {
                responsesInterNetwork = this.EndQueryLocal(asyncEnumerator.DequeueAsyncResult());
            }
            catch (Exception exception)
            {
                this.Logger.Error(exception, (int)EventId.NetSendReceiveFail, true);

                yield break;
            }

            try
            {
                this.BeginQueryLocal(hostName, QType.AAAA, QClassType.IN, asyncEnumerator.End(), null);
            }
            catch (Exception exception)
            {
                this.Logger.Verbose(exception, (int)EventId.NetSendReceiveFail);
            }

            yield return 1;

            try
            {
                responsesInterNetworkV6 = this.EndQueryLocal(asyncEnumerator.DequeueAsyncResult());
            }
            catch (Exception exception)
            {
                this.Logger.Verbose(exception, (int)EventId.NetSendReceiveFail);
            }

            // fill AddressList and aliases
            var addressList = new List<IPAddress>();
            var aliases = new List<string>();

            /*V4 Addresses*/
            foreach (AnswerResourceRecord answerrr in responsesInterNetwork.Answers)
            {
                if (answerrr.RRType == RecordType.A)
                {
                    addressList.Add(IPAddress.Parse(answerrr.Record.ToString()));
                    entry.HostName = answerrr.Name;
                }
                else
                {
                    if (answerrr.RRType == RecordType.CNAME)
                    {
                        aliases.Add(answerrr.Name);
                    }
                }
            }

            /*V6 Addresses*/
            if (responsesInterNetworkV6 != null)
            {
                foreach (AnswerResourceRecord answerrr in responsesInterNetworkV6.Answers)
                {
                    if (answerrr.RRType == RecordType.AAAA)
                    {
                        addressList.Add(IPAddress.Parse(answerrr.Record.ToString()));
                        entry.HostName = answerrr.Name;
                    }
                    else
                    {
                        if (answerrr.RRType == RecordType.CNAME)
                        {
                            aliases.Add(answerrr.Name);
                        }
                    }
                }
            }

            entry.AddressList = addressList.ToArray();
            entry.Aliases = aliases.ToArray();

            asyncEnumerator.Result = entry;
        }

        /// <summary>
        /// Resolves the async.
        /// </summary>
        /// <param name="asyncEnumerator">
        /// The async enumerator.
        /// </param>
        /// <param name="hostName">
        /// Name of the host.
        /// </param>
        /// <param name="cancellationToken">
        /// The cancellation token.
        /// </param>
        /// <returns>
        /// The <see cref="IEnumerator"/>.
        /// </returns>
        private IEnumerator<int> ResolveLocalAsync(
            AsyncEnumerator<IPHostEntry> asyncEnumerator, string hostName, CancellationToken cancellationToken)
        {
            Contract.Requires(asyncEnumerator != null);
            Contract.Requires(!string.IsNullOrEmpty(hostName));

            try
            {
                this.BeginMakeEntryLocal(hostName, asyncEnumerator.End(), null);
            }
            catch (Exception exception)
            {
                this.Logger.Error(exception, (int)EventId.NetSendReceiveFail, true);

                yield break;
            }

            yield return 1;

            IPHostEntry entry;

            try
            {
                entry = this.EndMakeEntryLocal(asyncEnumerator.DequeueAsyncResult());
            }
            catch (Exception exception)
            {
                this.Logger.Error(exception, (int)EventId.NetSendReceiveFail, true);

                yield break;
            }

            asyncEnumerator.Result = entry;
        }

        #endregion
    }
}